package com.stem.sms.authenticator.ali;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.IAcsClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import org.keycloak.authentication.AuthenticationFlowContext;
import org.keycloak.credential.CredentialModel;
import org.keycloak.credential.CredentialProvider;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.CredentialValidation;

import javax.ws.rs.core.MultivaluedMap;
import java.util.List;

/**
 * @author refined
 * @create 2019-11-12 10:59
 * @desc
 */
public class SmsUtils {


    /**
     * 发送验证码
     *
     * @param phone   手机号
     * @param context 认证流程上下文
     * @return true成功/false失败
     */
    public Boolean send(String phone, AuthenticationFlowContext context) {

        //这里测试的时候可以写死验证码,正式的时候下面的注释可以放开
        String code = "1234";

        CommonRequest commonRequest = SystemConfigProperties.commonRequest();
        IAcsClient iAcsClient = SystemConfigProperties.defaultProfile();
        ObjectMapper mapper = new ObjectMapper();
//        String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
//        Map<String, String> map = new HashMap<>(1);
//        map.put("code", code);
//        commonRequest.putQueryParameter("PhoneNumbers", phone);
//        CommonResponse response = new CommonResponse();
//        try {
//            commonRequest.putQueryParameter("TemplateParam", mapper.writeValueAsString(map));
//            response = iAcsClient.getCommonResponse(commonRequest);
//            SmsVO smsVO = mapper.readValue(response.getData(), SmsVO.class);
//
//            if ("OK".equals(smsVO.getCode())) {

        //根据（用户名）手机号查找用户
        UserModel userByUsername = context.getSession().users().getUserByUsername(phone, context.getRealm());
        context.setUser(userByUsername);
        //移除之前的验证码信息
        List<CredentialModel> storedCredentialsByType = context.getSession().userCredentialManager().getStoredCredentialsByType(context.getRealm(), context.getUser()
                , SMSAuthenticatorContstants.USR_CRED_MDL_SMS_CODE);
        for (CredentialModel credentialModel : storedCredentialsByType) {
            context.getSession().userCredentialManager().removeStoredCredential(context.getRealm(), context.getUser(), credentialModel.getId());
        }
        List<CredentialModel> storedCredentialsByType2 = context.getSession().userCredentialManager().getStoredCredentialsByType(context.getRealm(), context.getUser()
                , SMSAuthenticatorContstants.USR_CRED_MDL_SMS_EXP_TIME);

        for (CredentialModel credentialModel2 : storedCredentialsByType2) {
            context.getSession().userCredentialManager().removeStoredCredential(context.getRealm(), context.getUser(), credentialModel2.getId());
        }
        //添加新的验证码信息（添加成功后，keycloak用户的Credentials界面会有信息）
        System.out.println("code :" + code);
        CredentialModel credentialModel = new CredentialModel();
        credentialModel.setType(SMSAuthenticatorContstants.USR_CRED_MDL_SMS_CODE);
        credentialModel.setCredentialData(code);

        context.getSession().userCredentialManager().createCredential(context.getRealm(), context.getUser(), credentialModel);

        credentialModel.setType(SMSAuthenticatorContstants.USR_CRED_MDL_SMS_EXP_TIME);
        credentialModel.setCredentialData(String.valueOf(System.currentTimeMillis() + 300000));
        context.getSession().userCredentialManager().createCredential(context.getRealm(), context.getUser(), credentialModel);

        return true;
//            } else {
//                System.out.println(smsVO.getMessage());
//                return false;
//            }
//        } catch (ClientException | IOException e) {
//            e.printStackTrace();
//            return false;
//        }
    }

    public enum CODE_STATUS {
        /**
         * 验证成功
         */
        VALID,
        /**
         * 验证失败
         */
        INVALID,
        /**
         * 过期
         */
        EXPIRED
    }

    /**
     * 校验验证码
     *
     * @param context 上下文
     * @return CODE_STATUS
     */
    public CODE_STATUS validateCode(AuthenticationFlowContext context) {
        CODE_STATUS result = CODE_STATUS.INVALID;

        MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
        //获取页面输入的验证码
        String enteredCode = formData.getFirst(SMSAuthenticatorContstants.ANSW_SMS_CODE);
        //获取用户保存验证码
        String expectedCode = getCredentialValue(context, SMSAuthenticatorContstants.USR_CRED_MDL_SMS_CODE);
        String expTimeString = getCredentialValue(context, SMSAuthenticatorContstants.USR_CRED_MDL_SMS_EXP_TIME);

        System.out.println("Expected code = " + expectedCode + "    entered code = " + enteredCode);
        System.out.println("expTimeString code = " + expTimeString);

        if (expectedCode != null) {
            result = enteredCode.equals(expectedCode) ? CODE_STATUS.VALID : CODE_STATUS.INVALID;
            long now = System.currentTimeMillis();

            System.out.println("Valid code expires in " + (Long.parseLong(expTimeString) - now) + " ms");
            if (result == CODE_STATUS.VALID) {
                if (Long.parseLong(expTimeString) < now) {
                    result = CODE_STATUS.EXPIRED;
                }
            }
        }
        System.out.println("result : " + result);
        return result;
    }

    /**
     * 获取验证码和过期时间
     *
     * @param context 上下文
     * @param type    类型
     * @return value值
     */
    public static String getCredentialValue(AuthenticationFlowContext context, String type) {
        String result = null;
        List<CredentialModel> storedCredentialsByType = context.getSession().userCredentialManager()
                .getStoredCredentials(context.getRealm(), context.getUser());
        for (CredentialModel cred : storedCredentialsByType) {
            System.out.println("id:" + cred.getId() + cred.getType() + ":" + cred.getCredentialData());
            if (cred.getType().equals(type)) {
                result = cred.getCredentialData();
            }
        }

        return result;
    }
}
